#include "shuangpin.h"

#include "third_part/ini/SimpleIni.h"
#include "utility/logger.h"

#include <string.h>
#include <cctype>

namespace cpis
{
	namespace keyflow
	{
		static const char *_full_pinyin_list[] =
			{
				"ba", "bo", "bi", "bai", "bei", "bao", "ban", "ben", "bang", "beng", "bie", "biao", "bian", "bin", "bing", "bu",
				"pa", "po", "pi", "pai", "pei", "pao", "pou", "pan", "pen", "pang", "peng", "pie", "piao", "pian", "pin", "ping", "pu",
				"ma", "mo", "me", "mi", "mai", "mei", "mao", "mou", "man", "men", "mang", "meng", "mie", "miao", "miu", "mian", "min", "ming", "mu",
				"fa", "fo", "fei", "fou", "fan", "fen", "fang", "feng", "fu",
				"da", "de", "di", "dai", "dei", "dao", "dou", "dan", "den", "dang", "deng", "dong", "dia", "die", "diao", "diu", "dian", "ding", "du", "duo", "dui", "duan", "dun",
				"ta", "te", "ti", "tai", "tei", "tao", "tou", "tan", "tang", "teng", "tong", "tie", "tiao", "tian", "ting", "tu", "tuo", "tui", "tuan", "tun",
				"na", "ne", "ni", "nai", "nei", "nao", "nou", "nan", "nen", "nang", "neng", "nong", "nie", "niao", "niu", "nian", "nin", "niang", "ning", "nu", "nuo", "nuan", "nv", "nve",
				"la", "le", "li", "lai", "lei", "lao", "lou", "lan", "lang", "leng", "long", "lia", "lie", "liao", "liu", "lian", "lin", "liang", "ling", "lu", "luo", "luan", "lun", "lv", "lve",
				"ga", "ge", "gai", "gei", "gao", "gou", "gan", "gen", "gang", "geng", "gong", "gu", "gua", "guo", "guai", "gui", "guan", "gun", "guang",
				"ka", "ke", "kai", "kao", "kou", "kan", "ken", "kang", "keng", "kong", "ku", "kua", "kuo", "kuai", "kui", "kuan", "kun", "kuang",
				"ha", "he", "hai", "hei", "hao", "hou", "han", "hen", "hang", "heng", "hong", "hu", "hua", "huo", "huai", "hui", "huan", "hun", "huang",
				"ji", "jia", "jie", "jiao", "jiu", "jian", "jin", "jiang", "jing", "jiong", "ju", "juan", "jun", "jue",
				"qi", "qia", "qie", "qiao", "qiu", "qian", "qin", "qiang", "qing", "qiong", "qu", "quan", "qun", "que",
				"xi", "xia", "xie", "xiao", "xiu", "xian", "xin", "xiang", "xing", "xiong", "xu", "xuan", "xun", "xue",
				"zha", "zhe", "zhi", "zhai", "zhei", "zhao", "zhou", "zhan", "zhen", "zhang", "zheng", "zhong", "zhu", "zhua", "zhuo", "zhuai", "zhui", "zhuan", "zhun", "zhuang",
				"cha", "che", "chi", "chai", "chao", "chou", "chan", "chen", "chang", "cheng", "chong", "chu", "chuo", "chuai", "chui", "chuan", "chun", "chuang",
				"sha", "she", "shi", "shai", "shei", "shao", "shou", "shan", "shen", "shang", "sheng", "shu", "shua", "shuo", "shuai", "shui", "shuan", "shun", "shuang",
				"re", "ri", "rao", "rou", "ran", "ren", "rang", "reng", "rong", "ru", "ruo", "rui", "ruan", "run",
				"za", "ze", "zi", "zai", "zei", "zao", "zou", "zan", "zen", "zang", "zeng", "zong", "zu", "zuo", "zui", "zuan", "zun",
				"ca", "ce", "ci", "cai", "cao", "cou", "can", "cen", "cang", "ceng", "cong", "cu", "cuo", "cui", "cuan", "cun",
				"sa", "se", "si", "sai", "sao", "sou", "san", "sen", "sang", "seng", "song", "su", "suo", "sui", "suan", "sun",
				"ya", "ye", "yi", "yao", "you", "yan", "yang", "yong", "yin", "ying", "yu", "yuan", "yun", "yue",
				"wai", "wei", "wa", "wo", "wan", "wen", "wang", "weng", "wu",
				"a", "o", "e", "er", "ai", "ei", "ao", "ou", "an", "en", "ang", "eng"};

		// 默认映射声母: b --> b, p --> p, m --> m ...
		static const char *_default_slist[] =
			{
				"b",
				"p",
				"m",
				"f",
				"d",
				"t",
				"n",
				"l",
				"g",
				"k",
				"h",
				"j",
				"q",
				"x",
				// zh
				// ch
				// sh
				"r",
				"z",
				"c",
				"s",
				"y",
				"w",
				// "{'o', E_SID_O} //零声母音节的拼音(只有韵母)
		};

		static const char *_default_ylist[] = {"a", "o", "e", "i", "u", "v"}; // 默认映射韵母
		static int32_t _case_offset = 'a' - 'A';					  // 大小写字母偏移
		static bool _match_list[512];										  // for debug

		// 输入状态
		enum
		{
			E_IS_START,	  // 首次开始(直接解析无需分隔符)
			E_IS_CLEAN,	  // 前面的已经解析完毕(后续需要分隔符)
			E_IS_PENDING, // 全拼未决
			E_IS_HALFSP,  // 半双拼剩余一个字符
		};

		struct PinYinNode
		{
			PinYinNode() : valid(false), next(NULL) {}
			bool valid;		  // 截止到当前节点是否构成合法拼音
			PinYinNode *next; // next = new PinYinNode[128];
		};

		static PinYinNode *_pytree = NULL;
		static int32_t _ref_cnt = 0; // ShuangPin类实例计数，计数清零时，释放相关资源
		static std::map<std::string, int32_t> _pyidmap;

		//@ret: true: 遍历完当前拼音
		static bool ShuangPinInitPYTreeCore(PinYinNode *p, const char *c)
		{
			//TAOTICS_DEBUG_T("c:%d, c:%c", *c, *c);

			if (*c == '\0')
			{
				return true;
			}

			if (NULL == p[*c].next) // 未开辟此节点
			{
				p[*c - _case_offset].next = p[*c].next = new PinYinNode[128]();
			}

			if (ShuangPinInitPYTreeCore((PinYinNode *)p[*c].next, c + 1))
			{
				p[*c - _case_offset].valid = p[*c].valid = true;
			}

			return false;
		}

		static void ShuangPinInitPYTree(void)
		{
			_pytree = new PinYinNode[128]();
			for (auto p : _full_pinyin_list)
			{
				ShuangPinInitPYTreeCore(_pytree, p);
			}
		}

		static void ShuangPinDestroyPYTree(PinYinNode *p)
		{
			for (int32_t i = 'a'; i <= 'z'; i++)
			{
				if (NULL != p[i].next)
				{
					ShuangPinDestroyPYTree((PinYinNode *)p[i].next);
				}
			}
			delete[] p;
		}

// 搜狗双拼映射配置文件配置项
#define SOGOU_SP_SECTION_SHENGMU "声母"
#define SOGOU_SP_SECTION_YUNMU "韵母"
#define SOGOU_SP_SECTION_OSHENGMU "零声母音节的韵母"

		static ShuangPinMap LoadSogouIniBySimpleIni(CSimpleIni &ini_sp, ShuangPinMap &spmap)
		{
			auto &smap = spmap.smap;
			auto &ymap = spmap.ymap;
			auto &osmap = spmap.osmap;

			std::list<CSimpleIni::Entry> keys;

			// 读取声母映射
			ini_sp.GetAllKeys(SOGOU_SP_SECTION_SHENGMU, keys);
			for (auto &s : keys)
			{
				auto key = ini_sp.GetValue(SOGOU_SP_SECTION_SHENGMU, s.pItem);
				smap[key[0]] = s.pItem;
			}
			keys.clear();
			// 读取韵母映射
			ini_sp.GetAllKeys(SOGOU_SP_SECTION_YUNMU, keys);
			for (auto &y : keys)
			{
				auto key = ini_sp.GetValue(SOGOU_SP_SECTION_YUNMU, y.pItem);
				ymap[key[0]].push_back(y.pItem);
			}
			keys.clear();
			// 读取零声母映射
			ini_sp.GetAllKeys(SOGOU_SP_SECTION_OSHENGMU, keys);
			for (auto &y : keys)
			{
				auto key = ini_sp.GetValue(SOGOU_SP_SECTION_OSHENGMU, y.pItem);
				osmap[key] = y.pItem;
			}
			return spmap;
		}

		ShuangPinMap LoadSogouShuangPinMapByFilePath(const char *filename)
		{
			ShuangPinMap spmap;

			CSimpleIni ini_sp;
			ini_sp.SetUnicode();
			SI_Error err = ini_sp.LoadFile(filename);
			if (err != SI_OK)
			{
				TAOTICS_DEBUG_T("Error: load ini file error, code: [%d], ini file: [%s]", err, filename);
				return spmap;
			}

			return LoadSogouIniBySimpleIni(ini_sp, spmap);
		}

		ShuangPinMap LoadSogouShuangPinMapByString(const char *content)
		{
			ShuangPinMap spmap;

			CSimpleIni ini_sp;
			ini_sp.SetUnicode();
			SI_Error err = ini_sp.LoadData(content);
			if (err != SI_OK)
			{
				TAOTICS_DEBUG_T("Error: load ini data error, code: [%d], ini data: [%s]", err, content);
				return spmap;
			}

			return LoadSogouIniBySimpleIni(ini_sp, spmap);
		}

		ShuangPinMap LoadDefaultShuangPinMapByFilePath(const char *filename)
		{
			return LoadSogouShuangPinMapByFilePath(filename);
		}

		ShuangPinMap LoadDefaultShuangPinMapByString(const char *content)
		{
			return LoadSogouShuangPinMapByString(content);
		}

		ShuangPinMap LoadShuangPinMapByFilePath(const char *type, const char *filename)
		{
			if (strcmp("default", type) == 0)
			{
				return LoadDefaultShuangPinMapByFilePath(filename);
			}
			else if (strcmp("sogou", type) == 0)
			{
				return LoadSogouShuangPinMapByFilePath(filename);
			}
			else
			{
				ShuangPinMap spmap;
				return spmap;
			}
		}

		ShuangPinMap LoadShuangPinMapByString(const char *type, const char *content)
		{
			if (strcmp("default", type) == 0)
			{
				return LoadDefaultShuangPinMapByString(content);
			}
			else if (strcmp("sogou", type) == 0)
			{
				return LoadSogouShuangPinMapByString(content);
			}
			else
			{
				ShuangPinMap spmap;
				return spmap;
			}
		}

		CShuangPin::CShuangPin()
			: _full_pinyin_table{NULL},
			  _valid_key_table{false},
			  _input_status(E_IS_START),
			  _pending_len(0),
			  _valid_pylen(0),
			  _cur_pynode(NULL)
		{
			auto &_py_input = _full_pinyin.fpy;
			auto &_osp = _full_pinyin.py;

			_ref_cnt++;
			if (1 == _ref_cnt)
			{
				for (int32_t i = 0; i < sizeof(_full_pinyin_list) / sizeof(const char *); i++)
				{
					_pyidmap[_full_pinyin_list[i]] = i;
				}
			}
			//_input_status = E_IS_START;
			//_py_input.clear();
			_py_input.reserve(1024);
			_osp.reserve(256);
			//_osp.clear();
			//_pending_len = _valid_pylen = 0;
		}

		CShuangPin::~CShuangPin()
		{
			_ref_cnt--;
			if (0 == _ref_cnt)
			{
				_pyidmap.clear();
				if (NULL != _pytree)
				{
					ShuangPinDestroyPYTree(_pytree);
					_pytree = NULL;
				}
			}
		}

		int32_t CShuangPin::Init(const ShuangPinMap &spmap, bool enable_fullpinyin)
		{
			auto &smap = spmap.smap;
			auto &ymap = spmap.ymap;
			auto &osmap = spmap.osmap;

			// 初始化声母索引表:_sid_table
			memset(_full_pinyin_table, 0x00, sizeof(_full_pinyin_table));
			memset(_valid_key_table, false, sizeof(_valid_key_table));
			memset(_match_list, false, sizeof(_match_list));

			// 所有字母和分隔符都是合法字符
			_valid_key_table['\''] = true;
			for (int32_t i = 'a'; i <= 'z'; i++)
			{
				_valid_key_table[i] = _valid_key_table[i - _case_offset] = true;
			}

			std::map<char, std::string> tsmap;
			// 加载声母固定映射
			for (auto s : _default_slist)
			{
				tsmap[s[0]] = s;
			}
			// 读取声母映射配置
			for (auto kv : smap)
			{
				for (auto &s : kv.second)
				{
					s = tolower(s);
				}
				tsmap[tolower(kv.first)] = kv.second;
				_valid_key_table[toupper(kv.first)] = true;
				_valid_key_table[tolower(kv.first)] = true;
			}

			std::map<char, std::vector<std::string>> tymap;
			// 加载韵母固定映射
			for (auto y : _default_ylist)
			{
				tymap[y[0]].push_back(y);
			}
			// 读取声母映射配置
			for (auto kv : ymap)
			{
				for (auto yun : kv.second)
				{
					for (auto &y : yun)
					{
						y = tolower(y);
					}
					tymap[tolower(kv.first)].push_back(yun);
					_valid_key_table[toupper(kv.first)] = true;
					_valid_key_table[tolower(kv.first)] = true;
				}
			}

			int32_t match_cnt = 0;
			for (auto &skv : tsmap)
			{
				for (auto &ykv : tymap)
				{
					for (auto &yun : ykv.second)
					{
						auto it = _pyidmap.find(skv.second + yun);
						if (it != _pyidmap.end())
						{
							auto p = _full_pinyin_list[it->second];
							_full_pinyin_table[skv.first][ykv.first] = p;
							_full_pinyin_table[toupper(skv.first)][toupper(ykv.first)] = p;
							_full_pinyin_table[toupper(skv.first)][ykv.first] = p;
							_full_pinyin_table[skv.first][toupper(ykv.first)] = p;
							if (_match_list[it->second])
							{
								TAOTICS_DEBUG_T("Warning: double match, py:%s, s:%c, y:%c", p, skv.first, ykv.first);
							}
							else
							{
								_match_list[it->second] = true;
								match_cnt++;
							}
						}
					}
				}
			}

			// 解析零声母拼音映射
			for (auto kv : osmap)
			{
				_valid_key_table[toupper(kv.first[0])] = true;
				_valid_key_table[tolower(kv.first[0])] = true;
				_valid_key_table[toupper(kv.first[1])] = true;
				_valid_key_table[tolower(kv.first[1])] = true;

				for (auto &y : kv.second)
				{
					y = tolower(y);
				}
				auto it = _pyidmap.find(kv.second);
				if (it == _pyidmap.end())
				{
					TAOTICS_DEBUG_T("Warning: unknown pinyin:%s", kv.second.c_str());
					continue;
				}
				auto p = _full_pinyin_list[it->second];
				_full_pinyin_table[toupper(kv.first[0])][toupper(kv.first[1])] = p;
				_full_pinyin_table[tolower(kv.first[0])][toupper(kv.first[1])] = p;
				_full_pinyin_table[tolower(kv.first[0])][tolower(kv.first[1])] = p;
				_full_pinyin_table[toupper(kv.first[0])][tolower(kv.first[1])] = p;
				if (_match_list[it->second])
				{
					TAOTICS_DEBUG_T("Warning: double match, py:%s, sy:%c%c", p, kv.first[0], kv.first[1]);
				}
				else
				{
					_match_list[it->second] = true;
					match_cnt++;
				}
			}

			if (sizeof(_full_pinyin_list) / sizeof(const char *) != match_cnt)
			{
				TAOTICS_DEBUG_T("Warning: can not match all pinyin(%d), match cnt:%d", static_cast<int32_t>(sizeof(_full_pinyin_list) / sizeof(const char *)), match_cnt);
				TAOTICS_DEBUG_T("PinYin not matched:");

				for (int32_t i = 0; i < sizeof(_full_pinyin_list) / sizeof(const char *); i++)
				{
					if (!_match_list[i])
					{
						TAOTICS_DEBUG_T("\t%s", _full_pinyin_list[i]);
					}
				}
			}

			_enable_fullpinyin = enable_fullpinyin;
			if (_enable_fullpinyin)
			{
				if (NULL == _pytree)
				{
					ShuangPinInitPYTree();
				}
				_cur_pynode = _pytree;
			}
			return 0;
		}

		void CShuangPin::SearchPinYin(const char *c)
		{
			if ('\0' == *c)
			{
				return;
			}
			auto p = _cur_pynode[*c].next;
			if (NULL != p)
			{
				_pending_len++;
				if (_cur_pynode[*c].valid)
				{
					_valid_pylen = _pending_len;
				}
				_cur_pynode = p;
				SearchPinYin(c + 1);
			}
		}

		void CShuangPin::DecodeSP(std::string &isp)
		{
			const char *p = NULL;
			auto &_py_input = _full_pinyin.fpy;
			auto &_osp = _full_pinyin.py;

			switch (_input_status)
			{
			case E_IS_START:
			LABEL_IS_START:
                if('\'' == isp[0])
                {
                    //_input_status = E_IS_START;
                    _osp.push_back('\'');
                    _py_input.push_back('\'');
                    isp.erase(0,1);
                    if(isp.size() > 0)
                    {
                        goto LABEL_IS_START;
                    }
                    else
                    {
                        _input_status = E_IS_START;
                        break;
                    }
                }
                // isp[0] != '\''
                if (isp.size() == 1)
                {
            
                    _input_status = E_IS_HALFSP;
                    _osp.push_back(isp[0]);
                    _py_input.push_back(isp[0]);
                    //_cur_pynode = _pytree;
                    // isp.erase(0,1)
                    //_pending_len = _valid_pylen = 0;
                }
				else // isp.size() > 1
				{
					p = DecodeSingleSP(isp[0], isp[1]);
					if (NULL == p)
					{
					    _osp.push_back(isp[0]);
					    _py_input.push_back(isp[0]);
						isp.erase(0, 1);
					    goto LABEL_IS_CLEAN;
					}
					else
					{
						_input_status = E_IS_CLEAN;
						_osp += p;
						_py_input += p;
						isp.erase(0, 2);
						if (isp.size() > 0)
						{
							goto LABEL_IS_CLEAN;
						}
					}
				}
				break;

			case E_IS_CLEAN:
			LABEL_IS_CLEAN:
				//_input_status = E_IS_START;
				_osp.push_back('\'');
				_py_input.push_back('\'');
				if (isp[0] == '\'')
				{
					isp.erase(0, 1);
                    if(0 == isp.size())
                    {
                        _input_status = E_IS_START;
                        break;
                    }
				}
				goto LABEL_IS_START;
				break;

			case E_IS_HALFSP:
				// LABEL_IS_HALFSP:
				p = DecodeSingleSP(_py_input.back(), isp[0]);
				if (NULL == p)
				{
					//_input_status = E_IS_CLEAN;
					goto LABEL_IS_CLEAN;
				}
				else
				{
					if (tolower(_py_input.back()) == p[0])
					{
						_osp += p + 1;
						_py_input += p + 1;
					}
					else //zh ch sh, an(复合声母, 或者零声母拼音)
					{
						_osp.push_back('\b');
						_osp += p;
						_py_input.erase(_py_input.size() - 1);
						_py_input += p;
					}
					isp.erase(0, 1);
					if (isp.size() > 0)
					{
						goto LABEL_IS_CLEAN;
					}
					_input_status = E_IS_CLEAN;
				}
				break;

			default:
				break;
			}
		}

		void CShuangPin::DecodeMix(std::string &isp)
		{
			const char *p = NULL;
			int32_t old_plen = _pending_len;
			auto &_py_input = _full_pinyin.fpy;
			auto &_osp = _full_pinyin.py;
			const char *pending_input = _py_input.c_str() + _py_input.size() - old_plen;

			switch (_input_status)
			{
			case E_IS_START:
			LABEL_IS_START:
                if('\'' == isp[0])
                {
                    //_input_status = E_IS_START;
					_osp.push_back('\'');
					_py_input.push_back('\'');
                    isp.erase(0,1);
                    if(isp.size() > 0)
                    {
                        goto LABEL_IS_START;
                    }
                    _input_status = E_IS_START;
                    break;
                }
				SearchPinYin(isp.c_str());
				if (0 == _pending_len) //_valid_pylen == 0, i, v, u
				{
					if (isp.size() == 1) // 等待潜在双拼
					{
                        _input_status =  E_IS_HALFSP;
                        _osp.push_back(isp[0]);
                        _py_input.push_back(isp[0]);
						//_cur_pynode = _pytree;
						// isp.erase(0,1);
						//_valid_pylen = _pending_len = 0;
					}
					else // isp.size() > 1 //判断是否可以构成双拼
					{
						p = DecodeSingleSP(isp[0], isp[1]);
						if (NULL == p) // 无效双拼: 将首字母返回引擎,然后递归处理
						{
					        //_input_status = E_IS_CLEAN;
					        _osp.push_back(isp[0]);
					        _py_input.push_back(isp[0]);
							//_cur_pynode = _pytree;
							isp.erase(0, 1);
							//_valid_pylen =  _pending_len = 0;
						    goto LABEL_IS_CLEAN;
						}
						else // 构成双拼
						{
							_input_status = E_IS_CLEAN;
							_osp += p;
							_py_input += p;
							//_cur_pynode = _pytree;
							isp.erase(0, 2);
							//_valid_pylen = _pending_len = 0;
							if (isp.size() > 0)
							{
								goto LABEL_IS_CLEAN;
							}
						}
					}
				}
				else //_pending_len > 0
				{
					if (isp.size() == _pending_len)
					{
						_input_status = E_IS_PENDING;
						_osp += isp;
						_py_input += isp;
						//_cur_pynode = _pytree;
						// isp.clear()
						//_valid_pylen = _pending_len = 0;
					}
					else //_valid_pylen <= _pending_len < isp.size():
					{
						if (_valid_pylen == 0) // j jj lonj: 无效全拼，尝试双拼
						{
							if (1 == isp.size()) // 双拼未决
							{
                                _input_status = E_IS_HALFSP;
                                _osp.push_back(isp[0]);
                                _py_input.push_back(isp[0]);
                                _cur_pynode = _pytree;
								// isp.erase(0, 1);
								//_valid_pylen = _pending_len = 0;
							}
							else // isp.size() >= 2, 尝试双拼
							{
								p = DecodeSingleSP(isp[0], isp[1]);
								if (NULL == p) // 无效双拼: 将首字母(非分号)返回引擎,然后递归处理
								{
									//_input_status = E_IS_CLEAN;
									_osp.push_back(isp[0]);
									_py_input.push_back(isp[0]);
									_cur_pynode = _pytree;
									isp.erase(0, 1);
									/* _valid_pylen = */ _pending_len = 0;
									goto LABEL_IS_CLEAN;
								}
								else // 构成双拼
								{
									_input_status = E_IS_CLEAN;
									_osp += p;
									_py_input += p;
									_cur_pynode = _pytree;
									isp.erase(0, 2);
									/* _valid_pylen = */ _pending_len = 0;
									if (isp.size() > 0)
									{
										goto LABEL_IS_CLEAN;
									}
								}
							}
						}
#if 0 //绝对全拼优先，不再尝试双拼
						else if (_valid_pylen == 1) // 单字母拼音：a/o/e, 优先尝试双拼
						{
							p = DecodeSingleSP(isp[0], isp[1]);
							if (NULL == p) // 无效双拼: 将首字母返回引擎,然后递归处理
							{
								//_input_status = E_IS_CLEAN;
								_osp.push_back(isp[0]);
								_py_input.push_back(isp[0]);
								_cur_pynode = _pytree;
								isp.erase(0, 1);
								_valid_pylen = _pending_len = 0;
								goto LABEL_IS_CLEAN;
							}
							else // 构成双拼
							{
								_input_status = E_IS_CLEAN;
								_osp += p;
								_py_input += p;
								_cur_pynode = _pytree;
								isp.erase(0, 2);
								_pending_len = _valid_pylen = 0;
								if (isp.size() > 0)
								{
									goto LABEL_IS_CLEAN;
								}
							}
						}
#endif
						else //_valid_pylen > 0
						{
							//_input_status = E_IS_CLEAN;
							_osp.append(isp.c_str(), _valid_pylen);
							_py_input.append(isp.c_str(), _valid_pylen);
							_cur_pynode = _pytree;
							isp.erase(0, _valid_pylen);
							_pending_len = _valid_pylen = 0;
							goto LABEL_IS_CLEAN;
						}
					}
				}
				break;

			case E_IS_CLEAN:
			LABEL_IS_CLEAN:
				//_input_status = E_IS_START;
				_osp.push_back('\'');
				_py_input.push_back('\'');
				if (isp[0] == '\'')
				{
					isp.erase(0, 1);
                    if(0 == isp.size())
                    {
                        _input_status = E_IS_START;
                        break;
                    }
				}
				goto LABEL_IS_START;
				break;

			case E_IS_HALFSP:
				// LABEL_IS_HALFSP:
				p = DecodeSingleSP(_py_input.back(), isp[0]);
				if (NULL == p) // 无效双拼: 补充双引号后重新START
				{
					//_input_status = E_IS_CLEAN;
					//_cur_pynode = _pytree;
					// isp.erase(0, 1)
					//_valid_pylen = _pending_len = 0;
					goto LABEL_IS_CLEAN;
				}
				else // 构成双拼
				{
					if (tolower(_py_input.back()) == p[0])
					{
						_osp += p + 1;
						_py_input += p + 1;
					}
                    else //zh ch sh, an
                    {
                        _osp.push_back('\b'); // 删除SP前缀
                        _osp += p;
                        _py_input.erase(_py_input.size() - 1); // 删除SP前缀
                        _py_input += p;
                    }
					//_cur_pynode = _pytree;
					isp.erase(0, 1);
					//_pending_len = _valid_pylen = 0;
					if (isp.size() > 0)
					{
						goto LABEL_IS_CLEAN;
					}
                    _input_status = E_IS_CLEAN;
				}
				break;

			case E_IS_PENDING:
				// LABEL_IS_PENDING:
				SearchPinYin(isp.c_str());
				if (_pending_len - old_plen < isp.size()) // 全拼延展结束
				{
					if (_valid_pylen < 1) // 尝试双拼
					{
						p = DecodeSingleSP(pending_input[0], old_plen > 1 ? pending_input[1] : isp[0]);
						if (NULL == p) // 无效双拼: 将首字母返回引擎,然后递归处理
						{
							//_input_status = E_IS_CLEAN;
							// 删除pending,仅保留首字符
							for (int32_t i = 1; i < old_plen; i++)
							{
								_osp.push_back('\b');
							}
							isp.insert(0, pending_input + 1);
							_py_input.erase(_py_input.size() - old_plen + 1);
							_cur_pynode = _pytree;
							_valid_pylen = _pending_len = 0;
							goto LABEL_IS_CLEAN;
						}
						else // 构成双拼
						{
							_input_status = E_IS_CLEAN;
							// 删除pending, 仅保留_osp前缀
							for (int32_t i = 1; i < old_plen; i++)
							{
								_osp.push_back('\b');
							}
							if (tolower(pending_input[0]) == p[0])
							{
								_osp += p + 1;
							}
							else
							{
								_osp.push_back('\b');
								_osp += p;
							}
							_cur_pynode = _pytree;
							if (old_plen < 2)
							{
								isp.erase(0, 1);
							}
							else if (old_plen > 2)
							{
								isp.insert(0, pending_input + 2);
							}
							if (tolower(pending_input[0]) == p[0])
							{
								_py_input.erase(_py_input.size() - old_plen + 1);
								_py_input += p + 1;
							}
							else
							{
								_py_input.erase(_py_input.size() - old_plen);
								_py_input += p;
							}
							_valid_pylen = _pending_len = 0;
							if (isp.size() > 0)
							{
								goto LABEL_IS_CLEAN;
							}
						}
					}
					else // 截取有效拼音
					{
						//_input_status = E_IS_CLEAN;

						_cur_pynode = _pytree;
						if (_valid_pylen < old_plen)
						{
						    for (int32_t i = _valid_pylen; i < old_plen; i++)
						    {
						    	_osp.push_back('\b');
						    }
							_py_input.erase(_py_input.size() - old_plen + _valid_pylen);
							isp.insert(0, pending_input + _valid_pylen);
						}
						else if (_valid_pylen > old_plen)
						{
                            _osp.append(isp.c_str(), _valid_pylen - old_plen);
							_py_input.append(isp.c_str(), _valid_pylen - old_plen);
							isp.erase(0, _valid_pylen - old_plen);
						}
						_valid_pylen = _pending_len = 0;
						goto LABEL_IS_CLEAN;
					}
				}
				else // 继续延展
				{
					//_input_status = E_IS_PENDING;
					_osp += isp;
					_py_input += isp;
					//_cur_pynode = _pytree;
					// isp.clear();
					//_pending_len = _valid_pylen = 0;
				}
				break;
			default:
				break;
			}
		}

		const std::string &CShuangPin::Decode(const std::string &sp)
		{
			// auto &_py_input = _full_pinyin.fpy;
			auto &_osp = _full_pinyin.py;
            auto &comp = _full_pinyin.comp;

            comp += sp;
			_osp.clear();
			std::string isp(sp);
            
            if(sp.empty())
            {
                return _osp;
            }

			if (_enable_fullpinyin)
			{
				DecodeMix(isp);
			}
			else
			{
				DecodeSP(isp);
			}

			return _full_pinyin.py;
		}

		void CShuangPin::Clear()
		{
			auto &_py_input = _full_pinyin.fpy;
            auto &comp = _full_pinyin.comp;

			_input_status = E_IS_START;
			_cur_pynode = _pytree;
			_valid_pylen = _pending_len = 0;
			_py_input.clear();
            comp.clear();
		}
	}
}
